Contact Bounce: Why Capacitors Don’t Fix It

As part of our discussion around those Hall effect switches, I cautioned our Larval Engineer that she can’t use capacitors to “smooth out” mechanical switch bounce, even though all of her cronies and (most likely) her profs will advocate doing exactly that. The subject also came up at the local hackerspace when she showed off her project, so I should explain why capacitors don’t solve the problem.

Here’s some switch contact bounce:

Switch bounce - black panel-mount
Switch bounce – black panel-mount

Another push on the button, just to show how unpredictable the bounces can be:

Switch bounce - black panel-mount - 2
Switch bounce – black panel-mount – 2

Note the horizontal scale: 10 ms/div. The smaller glitches appear only by courtesy of the scope’s glitch-catching mode; they’re down around a few microseconds.

Now, let’s add the canonical 100 nF “debounce” capacitor in parallel with the contacts and record another set of bounces:

Switch bounce - black panel-mount - 100 nF cap
Switch bounce – black panel-mount – 100 nF cap

Notice that the switch contacts bounce in a completely unpredictable manner.

The pullup resistor is a rather stiff 1 kΩ, so the RC time constant is τ = 1 kΩ × 100 nF = 100 μs, but that applies only to the rising edges of the waveform as the switch opens. You can, indeed, see a slight rounding of those corners: the voltage requires about 5τ = 500 μs to reach 99% of the final voltage.

The capacitor also forms an LC tank circuit with the usual parasitic wiring inductance, producing spikes that exceed the supply voltage: that’s the first half-cycle of the tank oscillation as the switch opens. The Q is fairly low due to the relatively high resistance, so the oscillations die out quickly. If this were feeding a microcontroller’s input pin, its input protection diodes would clamp the spikes to one diode drop above the supply voltage and below 0 V, but that’s an entirely different study.

It should be obvious that adding the cap hasn’t done diddly squat to debounce the switch transition.

Increasing the pullup resistor to the usual 10 kΩ will increase the time constant to τ = 1 ms, round off the leading edges a bit more, and further reduce the Q. It won’t debounce the longest transitions, which are on the order of 20 ms for this particular switch. You can’t increase the pullup too much, because you want enough current through it to ensure a valid logic level despite external noise (which is also an entirely different study); 100 kΩ may be as much as you can stand.

But that’s just for glitches due to the switch opening. The closed switch puts a dead short across the capacitor, so the cap provides no filtering as the switch closes: the microcontroller will see every single low-going bounce. The photos show only bounces during the open→closed switch transition, but the closed→open transition can be equally ugly: yes, switches bounce closed as they open.

That means the microcontroller will see glitches as the switch opens.

So let’s increase the capacitor enough that the voltage can’t rise beyond the logic threshold until the switch stops bouncing. Ignoring LC tank effects, the voltage rises as 1 – e-t/τ, so we need that value to be less than 0.25 (for a bit of margin) of the supply voltage after the longest possible bounce as the switch opens. Let’s assume the switch has a single closed (low) glitch after a long time being open (high), at which time the voltage must still be under the logic threshold to prevent a false input. The datasheets only give the maximum bounce duration, if they give any bounce time at all, so let’s assume the longest bounce will be 60 ms.

That says τ = -60 ms / ln(0.75) = 210 ms. Given a 10 kΩ pullup, that’s C = 210 ms / 10 Ω = 21 μF.

No problem, right? Let’s just put a 22 μF electrolytic cap across every switch and be done with it!

Well, except for the fact that most pushbutton switches can’t tolerate that much energy through their contacts. Assuming a 100 mΩ resistance and ignoring stray inductance, the initial current will be 5 V / 100 mΩ = 50 A with a time constant of τ = 22 μF × 100 mΩ = 2 μs. At the usual 5 V logic supply, the cap stores 22 μF × (5 V)2 = 550 μJ of energy, so we’re now burning the switch contacts with a 250 W pulse. Some switches have a maximum energy rating to deter exactly this design blunder, but you should not assume the lack of such a rating means the switch can handle anything you throw at it.

No problem, let’s just put a resistor in series with the switch to reduce the initial current.

I think you can see where this is going, though, so I’ll leave all that as an exercise for the student.

Moral of the story: you must do debouncing in software by filtering the raw switch input. The trick will be to get that code right, which isn’t nearly as simple as you might think. In fact, the first half-dozen techniques you come up with won’t work, so use a dependable library and test the results… which is an entirely different study, too.

If it’s any consolation, I didn’t know this stuff when I was a Larval Engineer, either. In fact, I didn’t learn much of it until after I made all the usual mistakes…

19 thoughts on “Contact Bounce: Why Capacitors Don’t Fix It

  1. Ooh, you have touched a nerve here. This is one of my pet peeves (badly-debounced switches). Please excuse the following rant…

    Switch debouncing seems to be an unnecessarily black art. The principle is simple – detect the **first** change of state, then ignore further changes until you are certain the mechanics are finished (60 – 100 mS, perhaps).

    This is pretty easy to implement in software, especially if a real-time interrupt helps out in timing the delay.

    But some common software debouncing schemes take the approach of reporting the switch state only **after** the debounce period. This is typical of software integration schemes that count up when the switch is open, and down when it is closed, and report the switch state after a high or low integration threshold is reached. The problem is that this builds in a noticeable delay between the time the user pushes the switch and the time that the program takes action. So users think “this thing is sluggish”. Bad design, IMHO.

    Worse yet is the approach that requires not only a push but also a release before action is taken. Hopefully only seen as a rookie mistake, it will quickly convince a user that “the damn thing is broken” since it seems to ignore a pushed switch, only to come to life when the user releases the switch in disgust :-)

    On the hardware side, life becomes trivially easy if you have a double-throw switch controlling a set/reset flip flop. I recall a junior prof in one of my hardware design classes suggesting that you just wire two inverter sections head to tail in a ring, then use the switch to short the output of one stage or the other to ground. Presto! The world’s simplest R/S flip flop. True, the inverters have to able to take a joke, since the outputs have to fight the switch for a short time until the new state ripples around to the input. I’d never do this in an actual product, but as a practical matter it did work on the lab bench.

    OK, rant is done. I feel better now.

    1. reporting the switch state only **after** the debounce period

      Which, if I’m reading it correctly, is how the Arduino Bounce library works…

      requires not only a push but also a release

      Ah, like the Planet Bike Superflash pushbutton

      The first few things a new designer thinks of don’t work; I’ve got several examples hiding in my heap o’ code…

  2. It may seem like overkill if you have a microcontroller already in the mix, but if you need to operate something purely electrically you can use a 555 timer in one-shot (mono stable) configuration to debounce an input, with the button tied to the trigger pin and the output of the 555 being your debounced signal.

    The RC components should be chosen to set the mono stable pulse time to be greater than the maximum bounce period.

    In years gone by that would have been a disadvantageous solution based on part cost, but with ICs being vastly cheaper now it is fairly effective, particularly for hobbyist level work. Its easily understood and configured by a non-engineer, and the configurability of the pulse time can let you do interesting things electrically without even bothering your microcontroller (which can be helpful if you’ve already got it handling multiple interrupts).

    1. without even bothering your microcontroller

      And without introducing code complexities that require tedious debugging… I like it!

      But, for sure, somebody’s going to find an Olde Skool 555 with that totem-pole output crowbarring the power supply and wonder where all the glitches came from. I’m glad that is lost in the dustbin of history.

  3. forgive me if i misinterpreted your proposal, but it sounds like you are comparing software debounce to just a capacitor and pullup resistor on a switch. proper hardware debounce is done with a series resistor as well. and although the lag is worse for hardware debounce, it can often be worth the extra wait if processing time is limited.

    1. proper hardware debounce is done with a series resistor as well

      Well, I left that part as an exercise for the interested reader. It requires three discrete components (one of which will be a bulky cap) for each switch and, as you point out, imposes a long delay to filter out the worst-case bounces.

      Better, in this day & age, to wrap a dollop of (correctly written!) code around the raw switch input and make the problem Go Away. If the microcontroller is so small it can’t run that code, then the hardware has such a low per-unit cost that you can’t afford any discrete parts… [grin]

  4. Heh.. I’m an analog guy. I always find conversations about switch debouncing amusing.

    You’re right that a cacacitor can’t solve the bounce problem on its own, but the hardware solutions to the problem are well established.

    SR flip flops are the canonical debouncers of course.. the first hint of signal to the SET or RST pin changes the output, and after that you can pretty much tapdance on the input signal without changing the output. You do have to reset the flip flop to use the switch again, but that’s extremely doable.

    Sticking strictly to passives, you can debounce single-ended signals (the kind that come from normally open switches) with a simple RC divider. In the traces above, it looks like your switch pulls low, so connect a 1M resistor to VCC, connect the other end to a 100nF cap, and connect the other leg of the cap to GND. Then connect the switch to the node where the resistor meets the cap.

    When the switch is open, the cap will charge to VCC with an RC time constant of .1s. When you close the switch, the cap will discharge within microseconds (assuming low impedance on the other side of the switch), and any gaps in the signal from bounce will simply allow the cap to charge again. The difference in charge/discharge rates converts ‘bounce’ into ‘ripple’, and you can control the size of that ripple by changing the RC time constant.

    Personally, I like to throw in a Schmitt trigger so I get nice, clean transitions in the output. It also gives me a noise margin of about 2/3 VCC, so I can use smaller RC time constants and keep the switch responsive.

    People were debouncing switches long before microcontrollers were affordable, so saying you ‘must’ debounce in software overstates things a bit. Solutions exist in both realms, it isn’t a trivial problem in either realm, and as always, engineering is the art of making tradeoffs.

    1. engineering is the art of making tradeoffs

      Aye!

      What’s new and different is that, to a good first approximation, everybody entering the game uses something like an Arduino, wires a cheap switch directly to the inputs, turns on the microcontroller’s internal pullup, and slaps a cap across the switch to get rid of the bounces (because that’s what they’re told). Heartache and confusion ensue when the switch doesn’t seem to work right…

      Given that there’s no design going on and certainly no place for flipflops / RC filters / whatever, the right solution is to do it all in software. The Bounce library eliminates some intricate software that really isn’t anything a newbie can (or, honestly, should) hammer out. No shame in that: we all started as newbies!

      Thanks for the summary; I think folks will have a much better idea of the problem and solutions based on your descriptions.

  5. Back in my toymaker days in the 1980’s, cost was the overriding factor in a given circuit. You were certain that the switch was extremely bouncy. The preferred method was to use software, but sometimes there wasn’t enough code space left as the micro-controllers used were sub 50 cent, 4 bit, using the on-board rom and ram only. The method in both hardware and software was a SR flip-flop which was reset by a retriggerable one-shot. The retrigger was also tied to the SET signal so it did not start the delay until the switch had truly finished bouncing. While we used 74ls123 based hardware in the lab, they were too expensive to put in a high volume product, so, when an analog solution was dictated we used a small ceramic cap charged by the reverse leakage of a signal diode which produced a long linear ramp. This was discharged (retriggered) by an npn transistor with lower leakage than the diode. This worked in 99% of the products, but there were always exceptions.

    1. a small ceramic cap charged by the reverse leakage of a signal diode

      Now that would be tricky to specify, but I suppose if the overall time came out longer than some reasonable value, you didn’t really care about the exact numbers or the thermal stability. I like it!

    1. an off the shelf solution

      Two gotchas:

      Remember that pushbutton switches always get connected by jamming hookup wires into Arduino headers… [grin]

      I haven’t introduced her to the miracles of FREE SAMPLES yet, but that’s on the way. A college address should be convincing evidence of Good Intent these days, because of those billion-dollar dorm room startups. Right?

  6. My favorite debounce circuit uses two sections of a 40106 hex inverter, cascaded so the result is a non-inverting schmidt trigger. SPDT switch, with NC connected to ground, NO connected to the supply, and modest resistor (10K or so) from switch common terminal to the schmidt input. A larger resistor (100K or so) from output back to input makes the circuit bistable – when the switch is in either end position, the schmidt output indicates the switch position. When the switch wiper is between the two contacts (including bouncing at either end) it holds its current state. A modest cap can be added at the input node to add more noise immunity and/or a bit of delay.

    One advantage over a regular RS flip-flop approach is that the regular approach probably means connecting the switch wiper to ground and using a pull-up on R and S. That means one or the other pullup draws current all the time. The circuit described draws zero current except for CMOS leakage. I once built a debounced pushbutton in a small box with a BNC output and a 9V battery, to be used for manually triggering a cascaded pulse generator setup. The normal output state was low, so even with a load connected it only consumed steady state power when the button was pressed. Battery life was essentially equal to shelf life.

    1. SPDT switch

      There’s the rub, at least for the usual Arduino / microcontroller stuff that our Larval Engineer will be doing: everybody uses NO pushbutton switches and everybody’s surprised at the ensuing bounciness.

      In some future world, (I hope) she’ll refer back to this post to discover the Wisdom of the Ages (or maybe the Aged) and get her debouncing circuits right! [grin]

      a debounced pushbutton in a small box

      And nobody understood why that switch was the only one that worked properly. Well done!

  7. To play devils advocate: Even with the 22uF lytic the switch might live longer than the device, or users will just get used to having to push the switch harder/wiggle it… and anything that works without bouncing 99 out of 100 times will probably attribute the occasional bounce to user error. And the non technical user will assume they wore out the switch mechanically…

    (Don’t worry I would not *really* advocate that kind of design.)

    What might work depending on the switch characteristics is a *small* resistor on the discharge path (1-10 Ohm) to make the short and the switch slightly more alive… and if you pick a 22uF lytic for smallest size and cheapest price (as you would for such an application) you will likely end up with something having much too high an ESR anyway to actually cause a current pulse anywhere close to 50 amperes …

    1. much too high an ESR

      Hmmm, that sounds like an interesting project: measure the short-circuit current produced by different capacitors… [grin]

Comments are closed.